<template>
  <!-- mapbpx添加热力图 -->
  <div class="containerBox flex h-screen">
    <!-- 侧边控制面板 -->
    <el-aside
      class="sidebar-shadow bg-white flex-0.5v scrollbar-hide"
      :width="sidebarWidth"
      @collapse="handleCollapse"
    >
      <div class="p-4 border-b">
        <div class="flex items-center justify-between">
          <h1 class="text-xl font-bold text-primary">热力图控制面板</h1>
          <el-button
            icon="el-icon-s-fold"
            circle
            size="small"
            @click="toggleSidebar"
          ></el-button>
        </div>
      </div>

      <div class="p-4">
        <el-form label-width="120px" class="mb-6">
          <el-form-item label="底图选择">
            <el-radio-group v-model="baseMapType" @change="updateBaseMap">
              <el-radio-button label="tdt_vec">天地图矢量</el-radio-button>
              <el-radio-button label="tdt_img">天地图影像</el-radio-button>
              <el-radio-button label="mapbox">Mapbox默认</el-radio-button>
            </el-radio-group>
          </el-form-item>
        </el-form>

        <el-card class="mb-6">
          <template #header>
            <div class="flex items-center">
              <i class="fa fa-map-o mr-2 text-primary"></i>
              <span>热力图设置</span>
            </div>
          </template>

          <el-form label-width="120px">
            <el-form-item label="热力图半径">
              <el-slider
                v-model="heatmapRadius"
                :min="5"
                :max="100"
                :step="1"
                @change="updateHeatmap"
              >
                <template #tooltip="{ value }">半径: {{ value }}px</template>
              </el-slider>
              <el-input
                v-model.number="heatmapRadius"
                size="small"
                style="width: 80px; margin-top: 8px"
                @change="updateHeatmap"
              ></el-input>
            </el-form-item>

            <el-form-item label="热力图强度">
              <el-slider
                v-model="heatmapIntensity"
                :min="0.1"
                :max="5"
                :step="0.1"
                @change="updateHeatmap"
              >
                <template #tooltip="{ value }">强度: {{ value }}</template>
              </el-slider>
              <el-input
                v-model.number="heatmapIntensity"
                size="small"
                style="width: 80px; margin-top: 8px"
                @change="updateHeatmap"
              ></el-input>
            </el-form-item>

            <el-form-item label="热力图透明度">
              <el-slider
                v-model="heatmapOpacity"
                :min="0.1"
                :max="1"
                :step="0.05"
                @change="updateHeatmap"
              >
                <template #tooltip="{ value }">
                  透明度: {{ value.toFixed(2) }}
                </template>
              </el-slider>
              <el-input
                v-model.number="heatmapOpacity"
                size="small"
                style="width: 80px; margin-top: 8px"
                @change="updateHeatmap"
              ></el-input>
            </el-form-item>

            <el-form-item label="颜色渐变">
              <el-radio-group v-model="colorRamp" @change="updateHeatmap">
                <el-radio-button label="blue">蓝到红</el-radio-button>
                <el-radio-button label="green">绿到红</el-radio-button>
                <el-radio-button label="purple">紫到黄</el-radio-button>
                <el-radio-button label="rainbow">彩虹色</el-radio-button>
              </el-radio-group>
            </el-form-item>
          </el-form>
        </el-card>

        <el-card>
          <template #header>
            <div class="flex items-center">
              <i class="fa fa-info-circle mr-2 text-primary"></i>
              <span>数据信息</span>
            </div>
          </template>

          <div class="text-sm text-gray-600">
            <p class="mb-2">当前数据点: {{ points.length }}</p>
            <p class="mb-2">数据范围: 全国主要城市</p>
            <p>数据来源: 模拟生成</p>
          </div>

          <el-button
            type="primary"
            size="small"
            class="mt-4 w-full"
            @click="randomizeData"
          >
            <i class="fa fa-refresh mr-2"></i>
            随机生成数据
          </el-button>
        </el-card>
      </div>
    </el-aside>
    <!-- 地图容器 -->
    <div
      class="flex-1 relative transition-all duration-300 scrollbar-hide overflow-y-auto"
      :class="
        sidebarWidth === '64px' ? 'max-w-full' : 'max-w-[calc(100%-320px)]'
      "
    >
      <div id="map" class="map-container"></div>

      <!-- 地图控制按钮 -->
      <div class="absolute top-4 right-4 z-10 flex flex-col gap-2">
        <el-button type="primary" size="small" @click="zoomIn">
          <i class="fa fa-search-plus"></i>
        </el-button>
        <el-button type="primary" size="small" @click="zoomOut">
          <i class="fa fa-search-minus"></i>
        </el-button>
        <el-button type="primary" size="small" @click="resetView">
          <i class="fa fa-location-arrow"></i>
        </el-button>
      </div>

      <!-- 图例 -->
      <div
        class="absolute bottom-4 right-4 z-10 bg-white p-3 rounded-lg shadow-lg max-w-xs"
      >
        <h3 class="font-medium mb-2 text-sm">热力图图例</h3>
        <div class="flex items-center mb-1">
          <div class="w-4 h-4 rounded-full bg-blue-500 mr-2"></div>
          <span class="text-xs">低</span>
        </div>
        <div class="flex items-center mb-1">
          <div class="w-4 h-4 rounded-full bg-green-500 mr-2"></div>
          <span class="text-xs">中低</span>
        </div>
        <div class="flex items-center mb-1">
          <div class="w-4 h-4 rounded-full bg-yellow-500 mr-2"></div>
          <span class="text-xs">中高</span>
        </div>
        <div class="flex items-center">
          <div class="w-4 h-4 rounded-full bg-red-500 mr-2"></div>
          <span class="text-xs">高</span>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { onMounted, ref, nextTick } from 'vue'
import 'element-plus/dist/index.css'
import mapboxgl from 'mapbox-gl'
const sidebarWidth = ref('320px')
const baseMapType = ref('tdt_vec')
const heatmapRadius = ref(30)
const heatmapIntensity = ref(1.0)
const heatmapOpacity = ref(0.8)
const colorRamp = ref('blue')
const currentBaseMapType = ref('') //记录当前底图类型
let map: any
// 模拟热力图数据
const generateRandomPoints = (count = 500) => {
  const points: any = []

  // 全国主要城市坐标及权重
  const cities = [
    {
      name: '北京',
      lng: 116.4074,
      lat: 39.9042,
      weight: 80,
    },
    {
      name: '上海',
      lng: 121.4737,
      lat: 31.2304,
      weight: 90,
    },
    {
      name: '广州',
      lng: 113.2644,
      lat: 23.1291,
      weight: 75,
    },
    {
      name: '深圳',
      lng: 114.0579,
      lat: 22.5431,
      weight: 85,
    },
    {
      name: '成都',
      lng: 104.0658,
      lat: 30.5728,
      weight: 70,
    },
    {
      name: '杭州',
      lng: 120.1536,
      lat: 30.2874,
      weight: 78,
    },
    {
      name: '南京',
      lng: 118.7674,
      lat: 32.0415,
      weight: 68,
    },
    {
      name: '武汉',
      lng: 114.2985,
      lat: 30.5845,
      weight: 72,
    },
    {
      name: '重庆',
      lng: 106.5049,
      lat: 29.5331,
      weight: 65,
    },
    {
      name: '西安',
      lng: 108.9481,
      lat: 34.2631,
      weight: 60,
    },
    {
      name: '郑州',
      lng: 113.6654,
      lat: 34.7579,
      weight: 58,
    },
    {
      name: '长沙',
      lng: 112.9822,
      lat: 28.1127,
      weight: 55,
    },
    {
      name: '合肥',
      lng: 117.2856,
      lat: 31.8611,
      weight: 52,
    },
    {
      name: '福州',
      lng: 119.2959,
      lat: 26.0766,
      weight: 50,
    },
    {
      name: '济南',
      lng: 117.12,
      lat: 36.6512,
      weight: 53,
    },
    {
      name: '天津',
      lng: 117.1901,
      lat: 39.1256,
      weight: 62,
    },
    {
      name: '沈阳',
      lng: 123.429,
      lat: 41.7967,
      weight: 54,
    },
    {
      name: '哈尔滨',
      lng: 126.6425,
      lat: 45.7569,
      weight: 48,
    },
    {
      name: '长春',
      lng: 125.3245,
      lat: 43.8868,
      weight: 47,
    },
    {
      name: '石家庄',
      lng: 114.5149,
      lat: 38.0371,
      weight: 51,
    },
  ]

  // 基于城市生成随机点
  cities.forEach((city) => {
    // 在城市中心添加主要点
    points.push({
      lng: city.lng,
      lat: city.lat,
      weight: city.weight,
    })

    // 在城市周围生成一些随机点
    for (let i = 0; i < count / cities.length; i++) {
      const lngOffset = (Math.random() - 0.5) * 1.5 // ±0.75度经纬度偏移
      const latOffset = (Math.random() - 0.5) * 1.5
      const weight =
        Math.floor(Math.random() * city.weight * 0.7) + city.weight * 0.3

      points.push({
        lng: city.lng + lngOffset,
        lat: city.lat + latOffset,
        weight: Math.floor(weight),
      })
    }
  })

  return points
}
const points = ref(generateRandomPoints())
// 添加天地图底图
const addTianDiTuBaseMap = (type: string) => {
  if (!map) return

  // 保存当前热力图配置
  const heatmapConfig = {
    radius: heatmapRadius.value,
    intensity: heatmapIntensity.value,
    opacity: heatmapOpacity.value,
    colorRamp: colorRamp.value,
  }
  // 移除现有热力图层和数据源
  removeHeatmapLayers()
  // 记录上次底图类型
  const lastMapType = currentBaseMapType.value
  // 设置天地图底图样式
  if (type === 'tdt_vec' || type === 'tdt_img') {
    // 天地图底图配置
    const urlTemplate =
      type === 'tdt_vec'
        ? 'https://t0.tianditu.gov.cn/vec_w/wmts?tk=1e5a8aeb87fbf336c3d7780f91b7fdfc&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}'
        : 'https://t0.tianditu.gov.cn/img_w/wmts?tk=1e5a8aeb87fbf336c3d7780f91b7fdfc&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}'

    // 天地图底图样式
    const tdtStyle = {
      version: 8,
      sources: {
        'tdt-base': {
          type: 'raster',
          tiles: [urlTemplate],
          tileSize: 256,
          attribution: '© 天地图',
        },
      },
      layers: [
        {
          id: 'tdt-base',
          type: 'raster',
          source: 'tdt-base',
          minzoom: 0,
          maxzoom: 18,
        },
      ],
    }
    // 特殊处理天地图矢量和影像之间的切换
    if (
      (lastMapType === 'tdt_vec' && type === 'tdt_img') ||
      (lastMapType === 'tdt_img' && type === 'tdt_vec')
    ) {
      map.setStyle(tdtStyle)
      addHeatmapLayer(heatmapConfig)
    } else {
      // 非天地图内部切换的情况（如天地图<->Mapbox）
      map.setStyle(tdtStyle)
      // 样式加载完成后，添加热力图层
      map.once('style.load', () => {
        addHeatmapLayer(heatmapConfig)
      })
    }
    //特殊处理 Mapbox 样式：Mapbox 默认样式有不同的加载机制，需要单独处理
  } else if (type === 'mapbox') {
    // Mapbox默认底图
    map.setStyle('mapbox://styles/mapbox/light-v10')

    // 底图加载完成后重新添加热力图层
    map.once('style.load', () => {
      addHeatmapLayer(heatmapConfig)
    })
  }
  // 更新当前底图类型
  currentBaseMapType.value = type
}
// 移除热力图层和数据源的辅助函数
const removeHeatmapLayers = () => {
  if (map.getLayer('heatmap-points')) {
    map.removeLayer('heatmap-points')
  }
  if (map.getLayer('heatmap')) {
    map.removeLayer('heatmap')
  }
  if (map.getSource('heatmap-data')) {
    map.removeSource('heatmap-data')
  }
}
// 修改addHeatmapLayer函数，接受配置参数
const addHeatmapLayer = (
  config = {
    radius: heatmapRadius.value,
    intensity: heatmapIntensity.value,
    opacity: heatmapOpacity.value,
    colorRamp: colorRamp.value,
  },
) => {
  if (!map) return

  // 准备热力图数据
  const heatmapData = {
    type: 'FeatureCollection',
    features: points.value.map((point: any) => ({
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [point.lng, point.lat],
      },
      properties: {
        weight: point.weight,
      },
    })),
  }
  // 检查数据源是否已存在，如果存在则更新数据
  if (map.getSource('heatmap-data')) {
    map.getSource('heatmap-data').setData(heatmapData)
  } else {
    // 添加新数据源
    map.addSource('heatmap-data', {
      type: 'geojson',
      data: heatmapData,
    })
  }
  // 确保图层不存在再添加
  if (!map.getLayer('heatmap')) {
    map.addLayer({
      id: 'heatmap',
      type: 'heatmap',
      source: 'heatmap-data',
      maxzoom: 18,
      paint: {
        'heatmap-radius': config.radius,
        'heatmap-color': getColorRamp(config.colorRamp),
        'heatmap-intensity': config.intensity,
        'heatmap-opacity': config.opacity,
      },
    })
  }

  // 确保点图层不存在再添加
  if (!map.getLayer('heatmap-points')) {
    map.addLayer({
      id: 'heatmap-points',
      type: 'circle',
      source: 'heatmap-data',
      minzoom: 7,
      paint: {
        'circle-radius': 4,
        'circle-color': '#B42222',
        'circle-opacity': 0.6,
      },
    })
  }
}
// 更新热力图配置
const updateHeatmap = () => {
  if (!map || !map.getLayer('heatmap')) return

  map.setPaintProperty('heatmap', 'heatmap-radius', heatmapRadius.value)
  map.setPaintProperty('heatmap', 'heatmap-intensity', heatmapIntensity.value)
  map.setPaintProperty('heatmap', 'heatmap-opacity', heatmapOpacity.value)
  map.setPaintProperty(
    'heatmap',
    'heatmap-color',
    getColorRamp(colorRamp.value),
  )
}
// 更新底图
const updateBaseMap = () => {
  addTianDiTuBaseMap(baseMapType.value)

  // 重新添加热力图层，因为切换底图会重置样式
  if (map && map.getSource('heatmap-data')) {
    map.removeLayer('heatmap')
    map.removeLayer('heatmap-points')
    addHeatmapLayer()
  }
}
// 获取颜色渐变配置
const getColorRamp = (type: any) => {
  let colors: any = []

  switch (type) {
    case 'blue':
      colors = [
        'rgba(33, 102, 172, 0)',
        'rgba(66, 152, 189, 0.8)',
        'rgba(103, 191, 181, 0.8)',
        'rgba(171, 221, 164, 0.8)',
        'rgba(230, 245, 152, 0.8)',
        'rgba(255, 255, 178, 0.8)',
        'rgba(254, 217, 118, 0.8)',
        'rgba(254, 178, 76, 0.8)',
        'rgba(253, 141, 60, 0.8)',
        'rgba(252, 78, 42, 0.8)',
        'rgba(227, 26, 28, 0.8)',
        'rgba(177, 0, 38, 0.8)',
      ]
      break
    case 'green':
      colors = [
        'rgba(0, 68, 27, 0)',
        'rgba(0, 109, 44, 0.1)',
        'rgba(35, 139, 69, 0.2)',
        'rgba(65, 171, 93, 0.3)',
        'rgba(116, 196, 118, 0.4)',
        'rgba(161, 215, 106, 0.5)',
        'rgba(199, 233, 180, 0.6)',
        'rgba(229, 245, 224, 0.7)',
        'rgba(247, 252, 245, 0.8)',
      ]
      break
    case 'purple':
      colors = [
        'rgba(74, 20, 140, 0)',
        'rgba(106, 27, 154, 0.1)',
        'rgba(123, 31, 162, 0.2)',
        'rgba(142, 36, 170, 0.3)',
        'rgba(156, 39, 176, 0.4)',
        'rgba(186, 104, 200, 0.5)',
        'rgba(206, 147, 216, 0.6)',
        'rgba(224, 178, 255, 0.7)',
        'rgba(237, 201, 255, 0.8)',
        'rgba(245, 215, 255, 0.9)',
        'rgba(255, 230, 255, 1)',
      ]
      break
    case 'rainbow':
      colors = [
        'rgba(65, 105, 225, 0)',
        'rgba(70, 130, 180, 0.2)',
        'rgba(60, 179, 113, 0.4)',
        'rgba(255, 215, 0, 0.6)',
        'rgba(255, 140, 0, 0.8)',
        'rgba(255, 0, 0, 1)',
      ]
      break
  }

  // 构建Mapbox颜色表达式
  return [
    'interpolate',
    ['linear'],
    ['heatmap-density'],
    0,
    colors[0] || 'rgba(0, 0, 0, 0)',
    0.1,
    colors[1] || 'rgba(0, 0, 0, 0.1)',
    0.2,
    colors[2] || 'rgba(0, 0, 0, 0.2)',
    0.3,
    colors[3] || 'rgba(0, 0, 0, 0.3)',
    0.4,
    colors[4] || 'rgba(0, 0, 0, 0.4)',
    0.5,
    colors[5] || 'rgba(0, 0, 0, 0.5)',
    0.6,
    colors[6] || 'rgba(0, 0, 0, 0.6)',
    0.7,
    colors[7] || 'rgba(0, 0, 0, 0.7)',
    0.8,
    colors[8] || 'rgba(0, 0, 0, 0.8)',
    0.9,
    colors[9] || 'rgba(0, 0, 0, 0.9)',
    1,
    colors[10] || colors[colors.length - 1] || 'rgba(0, 0, 0, 1)',
  ]
}
// 随机生成新数据
const randomizeData = () => {
  points.value = generateRandomPoints()

  if (map && map.getSource('heatmap-data')) {
    // 更新数据源
    const heatmapData = {
      type: 'FeatureCollection',
      features: points.value.map((point: any) => ({
        type: 'Feature',
        geometry: {
          type: 'Point',
          coordinates: [point.lng, point.lat],
        },
        properties: {
          weight: point.weight,
        },
      })),
    }

    map.getSource('heatmap-data').setData(heatmapData)
  }
}
// 地图控制方法
const zoomIn = () => {
  if (map) map.zoomIn()
}
const zoomOut = () => {
  if (map) map.zoomOut()
}
const resetView = () => {
  if (map) map.setCenter([108.95, 34.27]).setZoom(4)
}
// 侧边栏控制
const toggleSidebar = () => {
  sidebarWidth.value = sidebarWidth.value === '320px' ? '64px' : '320px'
}
const handleCollapse = (collapsed: any) => {
  console.log('Sidebar collapsed:', collapsed)
}
onMounted(() => {
  nextTick(() => {
    initMap()
  })
})

const initMap = () => {
  // 设置Mapbox访问令牌
  mapboxgl.accessToken = import.meta.env.VITE_MapBox_TOKEN
  //   mapboxgl.accessToken = 'pk.eyJ1IjoiMTgzMDc3Mzc2NyIsImEiOiJjbDMzNHN4MWwwdG9lM2pwZjNmZ2R5Zjd1In0.GUKaR4wTfz8DCEFFlq4OLA'
  //   console.log("first",import.meta.env.VITE_MapBox_TOKEN)
  // 初始化Mapbox地图
  map = new mapboxgl.Map({
    container: 'map',
    style: {
      version: 8,
      sources: {},
      layers: [],
    },
    center: [108.95, 34.27], // 中国中心
    zoom: 4,
    attributionControl: false,
  })
  // 加载地图
  map.on('load', () => {
    // 添加天地图矢量底图
    addTianDiTuBaseMap(baseMapType.value)

    // 添加热力图层
    addHeatmapLayer()

    // // 添加地图控件 原生地图控件
    // map.addControl(new mapboxgl.NavigationControl(), 'top-right')
    // map.addControl(new mapboxgl.ScaleControl(), 'bottom-left')
  })
}
</script>

<style lang="scss" scoped>
.containerBox {
  //   display: flex;
  //   .right {
  //     flex: 1;
  //     .mapboxgl-canvas-container
  //       .mapboxgl-interactive
  //       .mapboxgl-touch-drag-pan
  //       .mapboxgl-touch-zoom-rotate {
  //       .mapboxgl-canvas {
  //         width: 100% !important;
  //         height: 100%;
  //       }
  //     }
  //   }
}
</style>
<style type="text/tailwindcss">
@layer utilities {
  .content-auto {
    content-visibility: auto;
  }
  .scrollbar-hide {
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .scrollbar-hide::-webkit-scrollbar {
    display: none;
  }
  .map-container {
    width: 100%;
    height: 100vh;
    overflow: hidden;
  }
  /* .canvas.mapboxgl-canvas {
        width: 100% !important;
        height: 100%;
    } */
  .sidebar-shadow {
    box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
  }
}
</style>
